#include <linux/pci.h>
#include <linux/platform_device.h> 
#include <linux/irq.h>  
#include <linux/log2.h> 
#include <linux/module.h>
#include <linux/moduleparam.h> 
#include <linux/slab.h> 
#include <linux/dmi.h> 
#include <linux/pci.h>
#include <acpi/acpi.h>
#include "pm_dbg.h"

spinlock_t      lock;
#define BUF_SIZE (1024*1024)

struct device_private {
	struct klist klist_children;
	struct klist_node knode_parent;
	struct klist_node knode_driver;
	struct klist_node knode_bus;
	struct list_head deferred_probe;
	void *driver_data;
	struct device *device;
};

struct pm_dbg_st {
    struct device dev; 
    //in the work show the dom_list dev
    struct work_struct work_pm_list;
    char *s_buf;
};

struct pm_dbg_st *pm_st;
static int pm_bus_rescan_devices(struct device *dev,void *data)
{

	printk("bus:%s ", dev->bus->name);
    if(dev->bus && dev->bus->dev_name)
	    printk("bus_dev:%s ", dev->bus->dev_name);
    if(dev_name(dev))
	    printk("%s ", dev_name(dev));

    return 0;
}

void pm_list_callback(struct device *dev, void *point)
{
    if(atomic_read(&dev->power.child_count) && 1)
    {
        struct bus_type *p_bus;
        p_bus = dev->bus;
        if(!p_bus)
        {
            printk("zoucao dev:%s bus no find\n" ,dev_name(dev));
            return;
        }
        bus_for_each_dev(p_bus, NULL, NULL, pm_bus_rescan_devices);
    }

    return ;
}

static ssize_t
pm_dbg_show(struct device *pdev, struct device_attribute *attr, char *buf)
{ 
   schedule_work(&pm_st->work_pm_list);
   flush_work(&pm_st->work_pm_list);
   printk("%s \n", pm_st->s_buf);     
   return 0;
}

static ssize_t
pm_dbg_store(struct device *pdev, struct device_attribute *attr,
		    const char *buff, size_t size)
{
    return 0;
}

static DEVICE_ATTR(pm_dbg,S_IRUGO | S_IWUSR, pm_dbg_show , pm_dbg_store);

int pm_dbg_runtime_suspend(struct device *dev)
{
    printk("zoucao %s\n", __func__);
    return 0;
}

int pm_dbg_runtime_resume(struct device *dev)
{
    printk("zoucao %s\n", __func__);
    return 0;
}

int pm_dbg_runtime_idle(struct device *dev)
{
    printk("zoucao %s\n", __func__);
    return 0;
}

static void pm_dbg_release_dev(struct device *dev)
{
    printk("zoucao %s\n", __func__);
}

static int pm_dbg_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
{
    printk("zoucao %s\n", __func__);
    return 0;
}

int pm_dbg_dev_prepare(struct device *dev)
{
    printk("zoucao %s\n", __func__);
    return 0;
}

void pm_dbg_dev_complete(struct device *dev)
{
    printk("zoucao %s\n", __func__);
}

int pm_dbg_dev_suspend(struct device *dev)
{
    printk("zoucao %s\n", __func__);
    return 0;
}

int pm_dbg_dev_resume(struct device *dev)
{
    printk("zoucao %s\n", __func__);
    return 0;
}

int pm_dbg_dev_freeze(struct device *dev)
{
    printk("zoucao %s\n", __func__);
    return 0;
}

int pm_dbg_dev_thaw(struct device *dev)
{
    printk("zoucao %s\n", __func__);
    return 0;
}

int pm_dbg_dev_poweroff(struct device *dev)
{
    printk("zoucao %s\n", __func__);
    return 0;
}

int pm_dbg_dev_restore(struct device *dev)
{
    printk("zoucao %s\n", __func__);
    return 0;
}

static const struct dev_pm_ops pm_dbg_device_pm_ops = {
    .prepare =  pm_dbg_dev_prepare,
    .complete =	pm_dbg_dev_complete,
    .suspend =  pm_dbg_dev_suspend,
    .resume =	pm_dbg_dev_resume,
    .freeze =   pm_dbg_dev_freeze,
    .thaw =	pm_dbg_dev_thaw,
    .poweroff = pm_dbg_dev_poweroff,
    .restore =	pm_dbg_dev_restore,
#ifdef CONFIG_PM_RUNTIME
    .runtime_suspend =  pm_dbg_runtime_suspend,
    .runtime_resume =	pm_dbg_runtime_resume,
    .runtime_idle =	pm_dbg_runtime_idle,
#endif
};

struct device_type pm_dbg_device_type = {
    .name =	    "pm_dbg_dev_type",
    .release =	pm_dbg_release_dev,
    .uevent =   pm_dbg_dev_uevent,
    //.devnode =	pm_dbg_devnode,
#ifdef CONFIG_PM
    .pm =	    &pm_dbg_device_pm_ops,
#endif
};

static void workqueue_func(struct work_struct *work)
{
    printk("zoucao %s\n", __func__);
    memset(pm_st->s_buf, 0 , BUF_SIZE);
}
static int dev_bus_rumtime_init(void)
{
    int ret = 0;
    printk("zoucao %s\n", __func__);

    pm_st = kmalloc(sizeof(struct pm_dbg_st), GFP_KERNEL); 
    //pm_st = kmalloc(sizeof(struct pm_dbg_st)); 
    if (!pm_st)
    {
	    printk("pm_st get mem failed\n");
	    return 0;
    }

    memset(pm_st, 0, sizeof(struct pm_dbg_st));
    device_initialize(&pm_st->dev);
    pm_st->dev.init_name = "pm_dbg_dev";
    pm_st->dev.bus = NULL;
    pm_st->dev.type = &pm_dbg_device_type;
    pm_st->dev.groups = NULL;

    ret = device_add(&pm_st->dev);
    if (ret)
    {
	    printk("zoucao pm_debug add device failed ret:%d\n", ret);
	    return 0;
    }

    printk("zoucao add dev:%s \n", dev_name(&pm_st->dev));
    ret = device_create_file(&pm_st->dev ,&dev_attr_pm_dbg);
    if (ret)
    {
	    printk("zoucao pm_debug add sys device failed\n");
	    return 0;
    }

    INIT_WORK(&pm_st->work_pm_list ,workqueue_func); 
    pm_st->s_buf = vmalloc(BUF_SIZE);
    if(!pm_st->s_buf)
    {
        printk("zoucao vmalloc %d failed\n" ,BUF_SIZE);
        return -ENOMEM;
    }

    //schedule_delayed_work(&pm_st->work_pm_list, 0); 
    //schedule_work(&pm_st->work_pm_list); 
    ret = ts_dev_bus_init();
    if(ret)
    {
        printk("zoucao bus initail fail\n");
        return 1;
    }

    return 0;
}

void dev_bus_rumtime_exit(void)
{
    device_remove_file(&pm_st->dev ,&dev_attr_pm_dbg);
    device_del(&pm_st->dev);
    put_device(&pm_st->dev);

    ts_dev_bus_exit();
    vfree(pm_st->s_buf);
    kfree(pm_st);
    printk("zoucao %s\n", __func__);

}

